/*
    该模块负责远程代码的编译
*/

#pragma once

#include <iostream>
#include <string>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include "../common/util.hpp"
//#include "../common/log.hpp"
#include "../RPC/source/common/log.hpp"

namespace oj_compiler
{
    using namespace oj_util;
    //using namespace oj_log;

    class Compiler
    {
    public:
        static bool compile(const std::string &file_name)
        {
            pid_t pid = fork();
            if (pid < 0)
            {
                LOG(JsonMuduoRPC::FATAL, "内部错误，创建子进程失败");
                return false;
            }

            if (pid == 0)
            {
                // child
                // 创建/打开 保存错误信息的临时文件，并重定向标准错误
                umask(0);
                int _stderr = open(PathUtil::CompileErr(file_name).c_str(), O_CREAT | O_WRONLY, 0644);
                if (_stderr < 0)
                {
                    LOG(JsonMuduoRPC::WARNING, "%s 文件打开/创建失败", PathUtil::Stderr(file_name).c_str());
                    exit(1);
                }

                dup2(_stderr, 2); // 让标准错误fd指向_stderr指向的文件，即将标准错误信息写入到_stderr中

                // 进程程序替换，执行临时生成的代码文件
                // g++ -o .exe .cc -std=c++11
                //-D __COMPILE_ONLINE__：去掉代码中的条件编译选项
                //-Werror=return-type如果程序要求有返回值但是没有返回，将警告变成错误
                execlp("g++", "g++", "-Werror=return-type", "-o", PathUtil::Exe(file_name).c_str(),
                       PathUtil::Src(file_name).c_str(), "-std=c++11", "-D __COMPILE_ONLINE__", nullptr);

                LOG(JsonMuduoRPC::ERROR, "启动编译器 g++ 失败");
                exit(2);
            }
            // 父进程
            waitpid(pid, nullptr, 0);

            if (FileUtil::isFileExists(PathUtil::Exe(file_name)))
            {
                LOG(JsonMuduoRPC::INFO, "%s 文件编译成功", PathUtil::Src(file_name).c_str());
                return true;
            }

            LOG(JsonMuduoRPC::INFO, "%s 文件编译失败", PathUtil::Src(file_name).c_str());
            return false;
        }
    };
} // namespace oj_complie
